#ifndef XLCOMM_BASE_THREADPOOL_H_
#define XLCOMM_BASE_THREADPOOL_H_

#include <condition_variable>
#include <deque>
#include <functional>
#include <mutex>
#include <string>
#include <thread>
#include <vector>

#include "xlcomm/define.h"
#include "xlcomm/noncopyable.h"

namespace xlcomm {

// 固定线程数的线程池
class XLCOMM_API ThreadPool : noncopyable {
 public:
  using Task = std::function<void()>;

  ThreadPool(const std::string& name, int max_queue_size);
  ~ThreadPool();

  // 启动固定线程数的线程池
  void Start(int thread_num, const Task& thread_init_callback = Task());

  // 停止所有线程
  void Stop();

  // 添加待执行任务。如果任务队列已满，则阻塞等待；线程池停止后再调用会直接return
  // 调用者需保证'裸指针和std::ref引用入参'的生命周期
  // 注：C++14没有move-only版本std::function，所以不用重载 const& 和 &&
  void AddTask(Task task);

  // 尝试添加待执行任务。如果任务队列已满，直接返回false
  // bool TryAddTask(Task task);

  // 获取任务队列大小
  size_t QueueSize() const;

  // 获取线程池名字
  std::string name() const { return name_; }

 private:
  using TaskQueue = std::deque<Task>;

  // 取出一个任务。如果任务队列为空，则阻塞等待
  Task TakeOne();
  // 线程处理函数
  void ThreadProc();

  mutable std::mutex mutex_;
  std::condition_variable not_empty_;
  std::condition_variable not_full_;
  std::string name_;
  size_t max_queue_size_;
  std::vector<std::thread> threads_;
  TaskQueue task_queue_;
  bool running_;
  Task thread_init_callback_;
};

}  // namespace xlcomm

#endif  // XLCOMM_BASE_THREADPOOL_H_